package com.mazaiting.manager.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mazaiting.common.core.domain.result.Option;
import com.mazaiting.common.core.domain.result.ResultCode;
import com.mazaiting.common.core.ex.exceptions.BaseException;
import com.mazaiting.common.core.ex.exceptions.BusinessException;
import com.mazaiting.common.core.ex.exceptions.EmptyObjectException;
import com.mazaiting.web.holder.SpringContextHolder;
import com.mazaiting.web.utils.UserUtil;
import com.mazaiting.manager.constant.SystemConstant;
import com.mazaiting.manager.convert.IRoleConverter;
import com.mazaiting.manager.domain.entity.SysRole;
import com.mazaiting.manager.domain.entity.SysRoleMenu;
import com.mazaiting.manager.domain.entity.SysRolePermission;
import com.mazaiting.manager.domain.entity.SysUserRole;
import com.mazaiting.manager.domain.form.RoleForm;
import com.mazaiting.manager.domain.form.RoleResourceForm;
import com.mazaiting.manager.domain.query.RolePageQuery;
import com.mazaiting.manager.domain.vo.role.RolePageVO;
import com.mazaiting.manager.domain.vo.role.SysRoleDetailVO;
import com.mazaiting.manager.listeners.event.RuleRelationEvent;
import com.mazaiting.manager.mapper.ISysRoleMapper;
import com.mazaiting.manager.service.ISysRoleMenuService;
import com.mazaiting.manager.service.ISysRolePermissionService;
import com.mazaiting.manager.service.ISysRoleService;
import com.mazaiting.manager.service.ISysUserRoleService;
import com.mazaiting.mybatisplus.domain.vo.BasePageVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * sys_role角色表 服务实现类
 *
 * @author 党海亮
 * @since 2022-03-22
 */
@Service
@RequiredArgsConstructor
public class SysRoleServiceImpl extends ServiceImpl<ISysRoleMapper, SysRole> implements ISysRoleService {

    private final ISysUserRoleService sysUserRoleService;

    private final ISysRoleMenuService sysRoleMenuService;

    private final ISysRolePermissionService sysRolePermissionService;

    private final IRoleConverter roleConverter;
    @Override
    public List<Option<Long>> listRoleOptions() throws EmptyObjectException {
        // 查询数据
        List<SysRole> roleList = lambdaQuery()
                .ne(!UserUtil.isRoot(), SysRole::getCode, SystemConstant.ROOT_ROLE_CODE)
                .select(SysRole::getId, SysRole::getName)
                .orderByAsc(SysRole::getSort).list();

        // 实体转换
        return roleConverter.roles2Options(roleList);
    }

    @Override
    public BasePageVO<RolePageVO> listRolePages(RolePageQuery queryParams) throws EmptyObjectException {
        // 查询参数
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        // 关键字
        String keywords = queryParams.getKeywords();

        // 查询数据
        Page<SysRole> sysRolePage = lambdaQuery()
                .like(StringUtils.hasLength(keywords), SysRole::getName, keywords)
                .or()
                .like(StringUtils.hasLength(keywords), SysRole::getCode, keywords)
                // 非超级管理员不显示超级管理员角色
                .ne(!UserUtil.isRoot(), SysRole::getCode, SystemConstant.ROOT_ROLE_CODE)
                .select(SysRole::getId, SysRole::getName, SysRole::getCode)
                .page(new Page<>(pageNum, pageSize));
        // 实体转换
        Page<RolePageVO> rolePageVOPage = roleConverter.entity2Page(sysRolePage);
        return BasePageVO.success(rolePageVOPage);
    }

    @Override
    public SysRoleDetailVO findById(Long roleId) throws EmptyObjectException {
        SysRole sysRole = getById(roleId);
        if (Objects.isNull(sysRole)) {
            throw new EmptyObjectException(ResultCode.ROLE_NOT_EXIST);
        }
        return roleConverter.entity2VO(sysRole);
    }

    @Override
    public boolean save(RoleForm roleForm) throws BusinessException {
        // 将角色 ID 置空
        roleForm.setId(null);

        // 查询角色名称或角色码值是否存在
        Long count = lambdaQuery()
                .eq(SysRole::getCode, roleForm.getCode())
                .or()
                .eq(SysRole::getName, roleForm.getName())
                .count();
        if (count > 0) {
            throw new BusinessException(ResultCode.ROLE_EXIST);
        }

        // 实体转换
        SysRole sysRole = roleConverter.form2Entity(roleForm);

        boolean result = save(sysRole);
        // 刷新权限缓存
        if (result) {
            SpringContextHolder.publishEvent(new RuleRelationEvent());
        }
        return result;
    }

    @Override
    public boolean update(RoleForm roleForm) throws BaseException {
        // 角色 ID
        Long roleId = roleForm.getId();

        // 查询角色名称或角色码值是否存在
        Long count = lambdaQuery()
                .ne(SysRole::getId, roleForm.getId())
                .and(wrapper ->
                        wrapper.eq(SysRole::getCode, roleForm.getCode())
                                .or()
                                .eq(SysRole::getName, roleForm.getName()))
                .count();

        if (count > 0) {
            throw new BusinessException(ResultCode.ROLE_EXIST);
        }
        // 获取系统角色
        SysRole sysRole = getById(roleId);
        if (Objects.isNull(sysRole)) {
            throw new EmptyObjectException(ResultCode.ROLE_NOT_EXIST);
        }

        // 实体转换
        roleConverter.form2Entity(roleForm, sysRole);

        boolean result = updateById(sysRole);
        // 刷新权限缓存
        if (result) {
            SpringContextHolder.publishEvent(new RuleRelationEvent());
        }
        return result;
    }

    @Override
    public boolean delete(String ids) throws BusinessException {
        List<Long> roleIds = Arrays.stream(ids.split(",")).map(Long::parseLong).toList();
        if (CollectionUtil.isNotEmpty(roleIds)) {
            for (Long roleId : roleIds) {
                // 根据角色 ID 查询是否已分配角色
                Long count = sysUserRoleService.lambdaQuery().eq(SysUserRole::getRoleId, roleId).count();
                if (count > 0) {
                    throw new BusinessException(ResultCode.ROLE_ALLOC_USER);
                }
                // 删除角色菜单关系
                sysRoleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
                // 删除角色权限关系
                sysRolePermissionService.remove(new LambdaQueryWrapper<SysRolePermission>().eq(SysRolePermission::getRoleId, roleId));
            }
        }
        // 批量删除
        boolean result = this.removeByIds(roleIds);
        // 删除成功，刷新权限缓存
        if (result) {
            SpringContextHolder.publishEvent(new RuleRelationEvent());
        }
        return result;
    }

    @Override
    public RoleResourceForm getRoleResources(Long roleId) {
        RoleResourceForm roleResources = new RoleResourceForm();

        // 获取角色拥有的菜单ID集合
        List<Long> menuIds = sysRoleMenuService.listMenuIdsByRoleId(roleId);
        roleResources.setMenuIds(menuIds);

        // 获取角色拥有的权限ID集合
        List<Long> permIds = sysRolePermissionService.listPermIdsByRoleId(roleId);
        roleResources.setPermIds(permIds);

        return roleResources;
    }

    @Override
    public boolean updateRoleResource(Long roleId, RoleResourceForm roleResourceForm) {
        // 更新角色菜单
        boolean result = sysRoleMenuService.deleteByRoleId(roleId)
                // 新增角色菜单
                && sysRoleMenuService.save(roleId, roleResourceForm.getMenuIds())
                // 删除角色权限
                && sysRolePermissionService.deleteByRoleId(roleId)
                // 新增角色权限
                && sysRolePermissionService.save(roleId, roleResourceForm.getPermIds());
        // 如果更新成功, 则重新加载 redis 缓存
        if (result) {
            SpringContextHolder.publishEvent(new RuleRelationEvent());
        }
        return result;
    }

}
